9044. Одинокий
остров
Имеется множество островов,
соединенных односторонними мостами: если мост соединяет острова a и b, то мост может быть
использован только для перехода от a к b,
Вы не можете вернуться назад по этому мосту. Когда Вы находитесь на острове a,
то выбираете (равномерно и случайным образом) один из островов, на который можно
напрямую попасть с a через
односторонний мост, и переходите на этот остров. Вы застряните на острове, если
нельзя двигаться дальше. Гарантируется, что после того, как Вы покинете
какой-либо остров, то на него уже не сможете вернуться.
Найдите остров, на котором
Вы застряните с наибольшей вероятностью. Два острова считаются одинаково
вероятными, если абсолютная разность вероятностей попадания на них
≤ 10-9.
Вход. Первая строка содержит три
целых числа: количество островов n (1 ≤ n ≤ 200000), количество односторонних мостов m (1 ≤ m ≤ 500000) и номер r (1 ≤ r ≤ n) острова на котором Вы
сначала находитесь. Каждая из следующих m строк содержит два целых
числа ui и vi (1 ≤ ui, vi ≤ n)
описывающих односторонний мост из ui в vi.
Выход. Выведите номер острова, на
котором Вы застряните с наибольшей вероятностью. Если существует несколько
таких островов, то выведите их в порядке возрастания индексов (значения,
разделенные пробелом в одной строке).
Пример входа |
Пример выхода |
5 7 1 1 2 1 3 1 4 1 5 2 4 2 5 3 4 |
4 |
топологическая
сортировка
Запустим алгоритм Кана построения
топологическойсортировки. Для каждой вершины v
вычислим количество входящих InDegree[v] и исходящих OutDegree[v] из нее
ребер.
Обозначим через prob[v] вероятность оказаться в
вершине v. Изначально prob[r] = 1 для стартовой вершины r, для остальных вершин prob[v] = 0.
Далее для каждой вершины v в порядке топологической сортировки перебираем ребра (v, to) и увеличиваем значение prob[to] на prob[v] / OutDegree[v].
Застрять можно в вершине v, для которой OutDegree[v] = 0. Находим максимальное
значение среди prob[v], для которых OutDegree[v] = 0.
Пример
Промоделируем алгоритм Кана для
графа, заданного в условии. Возле вершин графа приписана вероятность попадания
в нее. Изначально (рисунок слева) вероятность нахождения во всех вершинах равна
0, кроме стартовой первой, вероятность пребывания в которой равна 1.
Первой вершиной топологического
порядка будет вершина 1. Из нее исходит 4 ребра, следовательно вероятность prob[1] = 1 будет разделена между 4 вершинами, а именно
значение prob[1] / 4 = 0.25 следует прибавить к prob[2], prob[3], prob[4] и prob[5].
Далее
вершина 2 будет занесена в топологический порядок. Из нее исходит два ребра. prob[2] / 2 = 0.125 следует
прибавить к prob[4] и prob[5] (левый рисунок снизу).
Следующей вершиной будет 3. Из нее исходит одно ребро. prob[3] / 1 = 0.25 прибавим к prob[4] (рисунок справа). Затем будут
обработаны вершины 4 и 5, однако они не содержат исходящих ребер и вероятности
пересчитываться не будут.
Тупиковая вершина (которая не
содержит исходящих ребер) с максимальной вероятностью попадания в нее имеет
номер 4. Такая вершина в графе одна.
Объявим константу Epsilon.
#define EPS 1e-9
Граф храним в списке смежности graph. Объявим рабочие массивы.
vector<vector<int> > graph;
vector<int> InDegree, OutDegree;
deque<int> q;
vector<double> prob;
Читаем входные данные. Инициализируем массивы.
scanf("%d %d %d", &n, &m, &r);
graph.assign(n + 1, vector<int>());
InDegree.assign(n + 1, 0);
OutDegree.assign(n + 1, 0);
Читаем и строим граф. Для каждой
вершины подсчитываем количество входящих и исходящих ребер.
for (i = 0; i < m; i++)
{
scanf("%d %d", &a,
&b);
graph[a].push_back(b);
OutDegree[a]++;
InDegree[b]++;
}
Заносим в очередь вершины, в
которые не входят ребра.
for (i = 1; i < InDegree.size(); i++)
if (InDegree[i] == 0) q.push_back(i);
Вероятность оказаться в вершине r равна 1. Для остальных вершин начальная вероятность быть там равна
0.
prob.resize(n + 1);
prob[r] = 1;
Запускаем алгоритм Кана нахождения
топологической сортировки.
while (!q.empty())
{
Извлекаем из очереди вершину v. Перебираем
ребра (v, to). Из вершины v исходит OutDegree[v] ребер. Вероятность нахождения в вершине v равна prob[v]. Следовательно вероятность попадания из v в to равна prob[v] / OutDegree[v]. Эту
вероятность и следует прибавить к prob[to].
v = q.front(); q.pop_front();
for (i = 0; i < graph[v].size(); i++)
{
to = graph[v][i];
prob[to] += prob[v] / OutDegree[v];
Уменьшаем количество входящих
ребер в вершину v.
InDegree[to]--;
Если в вершину to не входит ни
одно ребро, то заносим to в очередь.
if (InDegree[to] == 0) q.push_back(to);
}
}
Ищем максимальное значение
вероятности среди prob[v] при условии что из острова v нет выхода.
mx = 0;
for (i = 1; i <= n; i++)
if (OutDegree[i] == 0 && prob[i] > mx) mx = max(mx, prob[i]);
Выводим вершины (их может быть
несколько), на которых достигается максимальная вероятность.
for (i = 1; i <= n; i++)
if (OutDegree[i] == 0 && fabs(prob[i] - mx) <= EPS)
printf("%d ", i);